//------------------------------------------------------------------------------
// Fichiers d'ent�te utilis�s
//------------------------------------------------------------------------------
#include "Histogram.hpp"
#include "Tools/Logger.hpp"
#include <GL/gl.h>
#include <iostream>
#include <math.h>


//------------------------------------------------------------------------------
// Définition de constantes
//------------------------------------------------------------------------------
#define INVALID_VALUE -1
#define HISTOGRAM_HEIGHT 800

namespace ImageAnalysis
{

	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	Histogram::Histogram( int nbValues ):
	accumulatedNumberOfPixels(0),
	numberOfPixels(0),
	numberOfValues(nbValues),
	meanValue(INVALID_VALUE),
	standartDeviationValue(INVALID_VALUE)
	{
		// Création du tableau contenant le nombre de pixels par valeur et le nombre cumul�de pixels
		numberOfPixels = new int[numberOfValues];
		accumulatedNumberOfPixels = new int[numberOfValues];

		// Initialisation du tableau contenant le nombre de pixels par valeur
		for( int index = 0; index < numberOfValues; ++index )
		{
			numberOfPixels[index] = 0;
		}
	}

	//----------------------------------------------------------------------
	// Destructeur
	//----------------------------------------------------------------------
	Histogram::~Histogram( )
	{
		if( numberOfPixels != 0 )
		{	delete[] numberOfPixels; }

		if( accumulatedNumberOfPixels != 0 )
		{	delete[] accumulatedNumberOfPixels; }
	}


	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void Histogram::Draw( )
	{
		int indexMaximumValue 	  = GetIndexMaximumValue(); // valeur de gris pour laquelle le nombre de pixel est max
		int maximumNumberOfPixels = numberOfPixels[indexMaximumValue]; // nombre de pixels max

		unsigned char* histogramPixels = new unsigned char[HISTOGRAM_HEIGHT*numberOfValues];
		for( int index = 0; index < numberOfValues; ++index )
		{
			//histogramPixels[index] = (*255) / maxPixels;
			int histogramPicSize = (numberOfPixels[index]*HISTOGRAM_HEIGHT) / maximumNumberOfPixels;
			for( int indexPixel = 0; indexPixel < histogramPicSize; ++indexPixel )
			{
				histogramPixels[index + indexPixel*numberOfValues] = 255;
			}
	
		}
		glDrawPixels( numberOfValues, HISTOGRAM_HEIGHT, GL_LUMINANCE, GL_UNSIGNED_BYTE, histogramPixels );
	
		delete[] histogramPixels;
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	int Histogram::GetNumberOfPixel( int index )
	{
		return numberOfPixels[index];
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void Histogram::AddPixelToValue( int index )
	{
	    // Comptabilisation de la valeur du pixel
		++numberOfPixels[index];

		// Invalidation de la valeur de la moyenne et de l'�art type pour
		// forcer leur recalcul
		standartDeviationValue = INVALID_VALUE;
		meanValue = INVALID_VALUE;

		// Lancement du calcule de l'histogramme cumul�
		//computeAcculatedHistogram();
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	int Histogram::GetIndexMaximumValue( )
	{
		int maximumValueIndex = 0; // valeur de gris pour laquelle le nombre de pixels est max
	
		for( int index = 0; index < numberOfValues; ++index )
		{
			if( numberOfPixels[index] > numberOfPixels[maximumValueIndex] )
			{
				maximumValueIndex = index;
			}
		}
	
		return maximumValueIndex;
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	int Histogram::GetNumberOfValues( )
	{
		return numberOfValues;
	}

	//----------------------------------------------------------------------
    	//
    	//----------------------------------------------------------------------
	int Histogram::GetMeanValue()
	{
		// Equiprobabilité des valeurs de pixels donc l'espérence est
		// une simple
		if( meanValue == INVALID_VALUE )
		{
			int nbTotalPixels;
			nbTotalPixels = 0;
			meanValue = 0;
			for( int index = 0; index < numberOfValues; ++index )
			{
				meanValue += index * numberOfPixels[index];
				nbTotalPixels += numberOfPixels[index];
			}
			meanValue /= nbTotalPixels;
		}
		return meanValue;
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	int Histogram::GetStandardDeviation()
	{
		if( standartDeviationValue == INVALID_VALUE )
		{
			// Calcul de la moyenne
			int mean = GetMeanValue();
			
			// Calcul de la variance
			int nbTotalPixels;
			nbTotalPixels = 0;
			double localStandartDeviationValue = 0;
			for( int index = 0; index < numberOfValues; ++index )
			{
				localStandartDeviationValue += (index*index) * numberOfPixels[index];
				nbTotalPixels += numberOfPixels[index];
			}
			localStandartDeviationValue /= nbTotalPixels;
			
			// Suppression du carr� de la moyenne
			localStandartDeviationValue -= (mean*mean);
			
			// Calcul de l'�art type �partir de la variance
			localStandartDeviationValue = sqrt(localStandartDeviationValue);
			standartDeviationValue = (int)localStandartDeviationValue;
		}

		return standartDeviationValue;
	}

	//----------------------------------------------------------------------
    	//
	//----------------------------------------------------------------------
	void Histogram::computeAcculatedHistogram()
	{
		accumulatedNumberOfPixels[0] = numberOfPixels[0];
		for( int index = 1; index < numberOfValues; ++index )
		{
			accumulatedNumberOfPixels[index] = accumulatedNumberOfPixels[index-1] + numberOfPixels[index];

		}
	}

	//----------------------------------------------------------------------
    	// Permet de calculer le niveau de gris pour lequel la quantit�de
	// pixel de la zone prise dans l'intervalle [0, upperBound[ est �al au
	// pourcentage souhait�
	//----------------------------------------------------------------------
	int Histogram::GetIndexPercentil( float percentage, int upperBoundIndex )
	{
		int numberOfPixel = 0;
		for( int index = 0; index < upperBoundIndex; ++index )
		{
			numberOfPixel += numberOfPixels[index];
		}

		int index = 0;
		//std::cout << index << " " << accumulatedNumberOfPixels[0]/(float)numberOfPixel << std::endl;
		while( (index < upperBoundIndex) && ((accumulatedNumberOfPixels[index]/(float)numberOfPixel) <= percentage) )
		{
			++index;
		}

		return index;
	}

}

